package main

import (
	"context"
	"fmt"
	"time"
)

type Options struct {
	Interval time.Duration
}
//type OptionKey string  // key应该是可比较的类型，为了避免冲突，不应是string和其它内置类型。通常为自定义struct
type OptionKey struct {
	name string
}


func reqTask(ctx context.Context, name string) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("stop", name)
			return
		default:
			fmt.Println(name, "send request")


			// 在子协程中, 获取到传递的值，读取/修改该址
			op := ctx.Value(OptionKey{name:"options"}).(*Options)
			time.Sleep(op.Interval * time.Second)
		}
	}
}

// WithCancel
/*func main() {
	ctx, cancel := context.WithCancel(context.Background())

	// 创建了一个基于ctx的子Context，并携带了值options
	vctx := context.WithValue(ctx, OptionKey{name:"options"}, &Options{5})

	for i := 0; i < 10000; i++ {
		go reqTask(vctx, "worker" + strconv.Itoa(i))
	}
	time.Sleep(3 * time.Second)
	cancel()
	time.Sleep(20 * time.Second)
	
}
*/

// WithTimeout
func main() {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second * 2)

	go reqTask(ctx, "worker1")
	go reqTask(ctx, "worker1")

	time.Sleep(time.Second * 3)
	fmt.Println("before cancel")
	cancel()							// 因为timeout为2秒，所以在手工cancel之前，子协程已超时退出
	time.Sleep(time.Second * 3)

}